#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>

using namespace std;
using line_no = vector<string>::size_type;  
vector<string> file;                        //文件内容按行存储
map<string,set<line_no>> wm;                //内容到行号的映射
string cleanup_str(const string &word){
    string ret;
    for(auto it = word.begin() ; it != word.end() ; it++){
        if(!ispunct(*it))
            ret += tolower(*it);
    }
    return ret;
}
void input_text(ifstream& is){
    string text;
    while(getline(is,text)){ //从输入流中按行读取
        file.push_back(text);
        int n = file.size() - 1;
        istringstream line(text);
        string word;
        while(line >> word){
            wm[cleanup_str(word)].insert(n);
        }
    }
}
ostream &query_and_print(const string &sought , ostream& os){
    auto loc = wm.find(sought);
    if(loc == wm.end()){
        os << sought << "出现了0次" << endl;
    }else{
        auto lines = loc->second;
        os << sought << "出现了" << lines.size() << "次" << endl; //表示在多少行中出现 其实这个计数并不靠谱
        for(auto num:lines){
            os << "\t第" << num << "行出现了"  //换行输出
               <<*(file.begin() + num) << endl;
        }
        return os;
    }
}
void runQueries(ifstream &infile){
    input_text(infile);
    //此段程序使用do while或者while都毫无差别
    while(1){
        cout << "enter word to look for , or q to quit:";
        string s;
        if(!(cin >> s) || s == "q") break;
        query_and_print(s,cout) << endl; //返回是一个ostream类型 可以直接把返回结果输出 函数过程把内容打包并格式化
    }
}

int main(int argc,char **argv){
    ifstream infile;

    if(argc < 2 || !(infile.open(argv[1]) , infile)){
        cerr << argc << endl;
        cerr << "no input files!" << endl;
        return EXIT_FAILURE;
    }
    runQueries(infile);
    return 0;
}